﻿using ExcelDataReader;
using FPSO.HMI.Utils;
using FPSO.Models.Constant;
using FPSO.Models.Domain;
using FPSO.Models.ViewModel;
using FPSO.Services;
using FPSO.Services.Impl;
using FPSO.Services.Utils;
using Google.Protobuf.WellKnownTypes;
using Opc.Ua;
using OpcUaHelper;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Threading;
using System.Xml;
using System.Xml.Linq;
using FPSO.Models;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
using PrismMVVMLibrary.DesignTime;

namespace FPSO.HMI.Views
{
    /// <summary>
    /// OPCMonitor.xaml 的交互逻辑
    /// </summary>
    public partial class OPCMonitorView : UserControl
    {
        private OPCMonitorViewModel viewModel;

		/// <summary>
		/// taskTimer用于获取opc数据
		/// checkTaskTimer用于检查opc数据
		/// </summary>
		private DispatcherTimer taskTimer;

		//taskList用于保存所有舱室动作的基本设备操作列表，该列表里应包含所有舱室的操作动作，且操作列表唯一
		//allTaskList用于保存所有舱室动作的备选设备操作列表，有些舱室的操作动作可能没有北线方案
		private List<OpcTask> taskList;
		private List<OpcTask> allTaskList;

        private OPCUtil opcUtil;

        public OPCMonitorView()
        {
            InitializeComponent();

            viewModel = new OPCMonitorViewModel();

			taskList = new List<OpcTask>();
			allTaskList = new List<OpcTask>();

			UpdateAllOpcTags();

			this.DataContext = viewModel;
            this.opcUtil = new OPCUtil();

            taskTimer = new DispatcherTimer();
            taskTimer.Interval = TimeSpan.FromSeconds(5);
            taskTimer.Tick += TaskTimer_Tick;
            taskTimer.Start();
		}

		protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
		{
			base.OnPropertyChanged(e);
		}
		void UpdateAllOpcTags()
		{
			foreach (OPCTag tag in TankConstant.tagList_flammableGasStatus)
			{
				string name = tag.OpcName;
				if (tag.DispName != null)
					name = tag.DispName;
				viewModel.SetOpcTagValue_FlammableGasStatus(name, DateTime.MinValue, string.Empty, string.Empty, Colors.Red);
			}

			foreach (OPCTag tag in TankConstant.tagList_valveStatus)
			{
				string name = tag.OpcName;
				if (tag.DispName != null)
					name = tag.DispName;
				viewModel.SetOpcTagValue_ValveStatus(name, DateTime.MinValue, string.Empty, string.Empty, Colors.Red);
			}

			foreach (OPCTag tag in TankConstant.tagList_hardwireStatus)
			{
				string name = tag.OpcName;
				if (tag.DispName != null)
					name = tag.DispName;
				viewModel.SetOpcTagValue_HardwireStatus(name, DateTime.MinValue, string.Empty, string.Empty, Colors.Red);
			}

			foreach (OPCTag tag in TankConstant.tagList_pumpStatus)
			{
				string name = tag.OpcName;
				if (tag.DispName != null)
					name = tag.DispName;
				viewModel.SetOpcTagValue_PumpStatus(name, DateTime.MinValue, string.Empty, string.Empty, Colors.Red);
			}

			//DEBUG 此处应该加上根据测点状态判断按键状态的逻辑，但该功能仅用于测试，故省略该步骤
			//下面这部分通过界面按键实现舱室集成控制的功能暂时封掉
			return;
			allTaskList = GetTaskList();
			if (allTaskList.Count > 0)
			{
				OpcTask task0 = allTaskList[0];
				List<OPCTag> controlList = task0.TagList;
				foreach (OPCTag tag in controlList)
				{
					viewModel.SetOpcTagValue_CtrlPnts(tag.OpcName, DateTime.MinValue, string.Empty, string.Empty, Colors.Red);
				}
			}

			Style btnTaskStyle = (Style)FindResource("btnTaskStyle");
			foreach (OpcTask opcTask in allTaskList)
			{
				bool checkres = false;
				foreach(OpcTask opcTask0 in taskList)
				{
					if(opcTask0.TaskName == opcTask.TaskName)
					{
						checkres = true;
						break;
					}
				}
				if (checkres)
				{
					for(int i=0;i< panelTask.Children.Count;i++)
					{
						Button btnTask = (Button)panelTask.Children[i];
						List<OpcTaskStatus> opcTasks = (List<OpcTaskStatus>)btnTask.Tag;
						OpcTaskStatus opcTaskStatus = new OpcTaskStatus();
						opcTaskStatus.TaskStatus = false;
						opcTaskStatus.OpcTask = opcTask;
						opcTasks.Add(opcTaskStatus);
					}
				}
				else
				{
					Button btnTask = new Button();
					btnTask.Content = opcTask.TaskName;
					btnTask.Click += BtnTask_Click;

					List<OpcTaskStatus> opcTasks = new List<OpcTaskStatus>();
					OpcTaskStatus opcTaskStatus = new OpcTaskStatus();
					opcTaskStatus.TaskStatus = false;
					opcTaskStatus.OpcTask = opcTask;
					opcTasks.Add(opcTaskStatus);
					btnTask.Tag = opcTasks;

					btnTask.Style = btnTaskStyle;
					panelTask.Children.Add(btnTask);
					taskList.Add(opcTask);
				}
			}
		}

		private void BtnTask_Click(object sender, RoutedEventArgs e)
        {
            Button btnTask = (Button)sender;
			List<OpcTaskStatus> opcTasks = (List<OpcTaskStatus>)btnTask.Tag;

			Style normalStyle = (Style)this.FindResource("btnTaskStyle");
			Style activeStyle = (Style)this.FindResource("btnActiveTaskStyle");
			//如果是常规状态，则点击后下发控制指令，按键状态变成活动，由于tag已经被使用，只能通过按键状态判断当前任务是否下发
			if (btnTask.Style == normalStyle)
			{
				foreach(OpcTaskStatus opcTaskstatus in opcTasks)
				{
					OpcTask opcTask = opcTaskstatus.OpcTask;

					bool closeCheck = ValveOpenProcess(opcTask);
					//如果当前状态不满足缺省控制策略要求，则使用备选方案
					if (closeCheck)
					{
						btnTask.Style = activeStyle;
					}
					else
					{
						continue;
					}
				}
			}
			//如果已经是开状态，则需执行关的操作
			else
			{
				Dictionary<string, object> openComDic = new Dictionary<string, object>();
				foreach(OpcTaskStatus opcTaskstatus in opcTasks)
				{
					bool taskStatus = opcTaskstatus.TaskStatus;
					if(taskStatus)
					{
						OpcTask opcTask = opcTaskstatus.OpcTask;
						foreach (OPCTag tag in opcTask.TagList)
						{
							string status_tag = string.Format("{0}{1}", SysConfig.OPC_ADD_PRE, tag.OpcName);

							//[实船调试] 实船使用这部分
							//if (tag.OpcName.Contains("SCM_Open"))
							//{
							//	status_tag = tag.OpcName.Replace("SCM_Open", "SCM_Close");
							//	openComDic.Add(status_tag, 1);
							//	continue;
							//}

							//NOTICE 测试使用这部分
							//if (tag.OpcName.Contains("SCM_Open"))
							//{
							//	openComDic.Add(status_tag, 0);
							//	string opcname0 = tag.OpcName.Replace("SCM_Open", "StatusOpened");
							//	status_tag = string.Format("{0}{1}", SysConfig.OPC_ADD_PRE, opcname0);
							//	openComDic.Add(status_tag, 0);
							//	string opcname1 = tag.OpcName.Replace("SCM_Open", "StatusClosed");
							//	status_tag = string.Format("{0}{1}", SysConfig.OPC_ADD_PRE, opcname1);
							//	openComDic.Add(status_tag, 1);
							//}
						}
						if (openComDic.Count > 0)
						{
							try
							{
								opcUtil.SetOpcValues(openComDic);
							}
							catch (Exception ex)
							{
								MessageBox.Show(ex.Message, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
							}
						}
						btnTask.Style = normalStyle;
					}
				}	
			}
		}

		private bool ValveOpenProcess(OpcTask opcTask)
		{
			//此处分为通讯点检查和下发两个步骤
			List<OPCTag> closeCheckTags = new List<OPCTag>();
			Dictionary<string, object> openComDic = new Dictionary<string, object>();

			foreach (OPCTag tag in opcTask.TagList)
			{
				string status_tag = string.Format("{0}{1}", SysConfig.OPC_ADD_PRE, tag.OpcName);

				//[实船调试] 实船使用这部分
				if (tag.OpcName.Contains("SCM_Open"))
				{
					openComDic.Add(status_tag, 1);
					continue;
				}
				//NOTICE 测试使用这部分
				//if (tag.OpcName.Contains("StatusOpened"))
				//{
				//	openComDic.Add(status_tag, 1);
				//	string opcname = tag.OpcName.Replace("Opened", "Closed");
				//	foreach (OPCTag tag1 in opcTask.TagList)
				//	{
				//		if (tag1.OpcName.Contains(opcname))
				//		{
				//			status_tag = string.Format("{0}{1}", SysConfig.OPC_ADD_PRE, tag1.OpcName);
				//			openComDic.Add(status_tag, 0);
				//			continue;
				//		}
				//	}
				//}
				else
					closeCheckTags.Add(tag);
			}
			//检查需关闭的设备是否按要求关闭，如有不符合要求的，则返回false
			try
			{
				opcUtil.GetOpcValues(closeCheckTags);
			}
			catch (Exception ex)
			{
				MessageBox.Show(ex.Message, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
			}
			bool closeCheck = true;
			string closeCheckRes = "";
			foreach (OPCTag tag in closeCheckTags)
			{
				//DEBUG 这里需要确认下位机statusclosed的数据类型
				bool valStr = Convert.ToBoolean(tag.OpcValue.Value);
				if (valStr != true)
				{
					closeCheck = false;
				}
				closeCheckRes += string.Format("{0}:Value = {1}\n", tag.OpcName, tag.OpcValue.Value);
			}
			MessageBox.Show(closeCheckRes);
			//如果设备都按要求关闭，则可以下发开指令
			if (closeCheck)
			{
				try
				{
					opcUtil.SetOpcValues(openComDic);
				}
				catch (Exception ex)
				{
					MessageBox.Show(ex.Message, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
					//如果开启任务失败也返回任务执行失败的结果
					closeCheck = false;
				}
			}
			return closeCheck;
		}
        private void LoadBtn_Click(object sender, RoutedEventArgs e)
        {
			//先确认四个点表存在，并清空五个点表
			List<string> xmlnames = new List<string>();
			xmlnames.Add("opctag_tankstatus.xml");
			xmlnames.Add("opctag_valvestatus.xml");
			xmlnames.Add("opctag_pumpstatus.xml");
			xmlnames.Add("opctag_hardwirestatus.xml");
			xmlnames.Add("opctag_flammablegasstatus.xml");

			foreach (string xmlname in xmlnames)
			{
				XmlDocument xmlDocument = new XmlDocument();
				try
				{
					xmlDocument.Load(xmlname);
				}
				catch
				{
					XmlTextWriter xtw = new XmlTextWriter(xmlname, Encoding.UTF8);
					xtw.WriteStartDocument();

					xtw.WriteStartElement("Tags");
					xtw.WriteEndElement();

					xtw.WriteEndDocument();
					xtw.Close();
					xmlDocument.Load(xmlname);
				}
				XmlNode root = xmlDocument.SelectSingleNode("Tags");
				root.RemoveAll();
				xmlDocument.Save(xmlname);
			}

			//DEBUG 这里改为根据通讯测点表自动生成对应的系统通讯点表
			string path = "./commpnts.csv";
			List<string[]> commpnts = TaskUtils.ReadExcel(path);

			foreach (string[] commpnt in commpnts)
			{
				string des = commpnt[0];
				string add = commpnt[1];
				string modbusadd = commpnt[2];
				string type = commpnt[3];
				string id = commpnt[4];
				string targetxml = commpnt[5];

				//ADD ALARM LIST
				//在采集信号的时候就对信号做判定，设置预警及报警值
				//如果没有的则系统不为其设置预警和报警点，其报警状态由信号采集获得
				//string min0 = commpnt[6];
				//string min1 = commpnt[7];
				//string max1 = commpnt[8];
				//string max0 = commpnt[9];
				if(targetxml.Length > 0)
				{
					XmlDocument xmlDocument = new XmlDocument();
					string xmlName = string.Format(targetxml + ".xml");

					try
					{
						xmlDocument.Load(xmlName);
					}
					catch
					{
						xmlDocument.CreateComment(xmlName);
					}

					XmlNodeList nodes = xmlDocument.GetElementsByTagName("Tags");
					XmlNode TagsNode = xmlDocument.SelectSingleNode("Tags");
					if (nodes.Count == 0)
					{
						TagsNode = xmlDocument.CreateElement("Tags");
						xmlDocument.AppendChild(TagsNode);
					}

					XmlElement newTag = xmlDocument.CreateElement("Tag");
					newTag.SetAttribute("DBTag", des);
					newTag.SetAttribute("OPCTag", add);
					newTag.SetAttribute("OpcType", type);
					newTag.SetAttribute("Coeff", "1");
					TagsNode.AppendChild(newTag);
					xmlDocument.Save(xmlName);
				}
			}
			UpdateAllOpcTags();
			DataContext = viewModel;
        }
        //UpdateBtn_Click仅面向控制点，读取表格内的数据，点击该按键后下发
        private void UpdateBtn_Click(object sender, RoutedEventArgs e)
        {
			//点击后先获取控制因果图表格
			string fileNmaePath = "./20230404_货油舱控制系统因果图_V0.3.xlsx";
			DataSet dataSet = TaskUtils.ReadExcelToDataSet(fileNmaePath);
			if (dataSet.Tables.Count > 0)
			{
				DataTableCollection tables = dataSet.Tables;

				//cargoLoadTaskNames保存Task名称
				//cargoLoadTaskCloseValves保存需要检查关闭的阀门OPC地址
				//cargoLoadTaskClosePumps保存需要检查关闭的泵OPC地址
				//cargoLoadTaskOpenValves保存需要打开的阀门OPC地址
				//cargoLoadTaskOpenPumps保存需要打开的泵OPC地址
				List<string> cargoLoadTaskNames = new List<string>();
				List<List<string>> cargoLoadTaskCloseValves = new List<List<string>>();
				List<List<string>> cargoLoadTaskOpenValves = new List<List<string>>();
				List<List<string>> cargoLoadTaskClosePumps = new List<List<string>>();
				List<List<string>> cargoLoadTaskOpenPumps = new List<List<string>>();
				//读取货油舱注入控制序列
				foreach(DataTable cargoLoadTable in tables)
				{
					//DataTable cargoLoadTable = tables[0];
					DataRow dataRow1 = cargoLoadTable.Rows[0];
					object[] valveNames = dataRow1.ItemArray;

					for (int i = 4; i < cargoLoadTable.Rows.Count; i++)
					{
						DataRow dataRow = cargoLoadTable.Rows[i];
						object[] dataItems = dataRow.ItemArray;
						string tankname = dataItems[1].ToString();
						string actname = dataItems[2].ToString();
						cargoLoadTaskNames.Add(tankname + "_" + actname);

						List<string> cargoLoadTaskCloseValvei = new List<string>();
						List<string> cargoLoadTaskOpenValvei = new List<string>();
						List<string> cargoLoadTaskClosePumpi = new List<string>();
						List<string> cargoLoadTaskOpenPumpi = new List<string>();
						for (int j = 7; j < cargoLoadTable.Columns.Count; j++)
						{
							string valveName = Convert.ToString(valveNames[j]);
							string valveStatus = Convert.ToString(dataItems[j]);
							bool findcheck = false;
							//先在阀门序列里找
							foreach (OPCTag tag in TankConstant.tagList_valveStatus)
							{
								if (tag.DispName.Contains(valveName))
								{
									//DEBUG 直接对StatusOpened下发开指令，同时对同设备的StatusClosed下发关指令
									//实际过程应该对SCM_Open下发信号，再读取StatusOpened的状态
									//if (valveStatus.Contains("O") && (tag.OpcName.Contains("StatusOpened") || tag.OpcName.Contains("StatusClosed")))
									if (valveStatus.Contains("O") && tag.OpcName.Contains("SCM_Open"))
									{
										cargoLoadTaskOpenValvei.Add(tag.OpcName);
										//cargoLoadTaskOpenValvei.Add(tag.OpcName);
										findcheck = true;
									}
									else if (valveStatus.Contains("C") && tag.OpcName.Contains("StatusClosed"))
									{
										cargoLoadTaskCloseValvei.Add(tag.OpcName);
										findcheck = true;
									}
								}
							}
							//在泵序列里找，暂时不考虑控制泵
							//if (findcheck == false)
							//{
							//	foreach (OPCTag tag in tagList_pumpStatus)
							//	{
							//		if (tag.DispName == valveName)
							//		{
							//			if (valveStatus.Contains("O"))
							//			{
							//				cargoLoadTaskOpenPumpi.Add(tag.OpcName);
							//			}
							//			else if (valveStatus.Contains("C"))
							//			{
							//				cargoLoadTaskClosePumpi.Add(tag.OpcName);
							//			}
							//		}
							//	}
							//}
						}
						cargoLoadTaskCloseValves.Add(cargoLoadTaskCloseValvei);
						cargoLoadTaskOpenValves.Add(cargoLoadTaskOpenValvei);
						cargoLoadTaskClosePumps.Add(cargoLoadTaskClosePumpi);
						cargoLoadTaskOpenPumps.Add(cargoLoadTaskOpenPumpi);
					}
				}

				//DataTable cargoUnloadTable = tables[1];
				//DataTable cargoSwapTable = tables[2];
				//DataTable ballastLoadTable = tables[3];
				//DataTable ballastUnloadTable = tables[4];

				//根据任务名称和对应设备状态更新opctask.xml
				XmlDocument xmlDocument = new XmlDocument();
				try
				{
					xmlDocument.Load("opctask.xml");
				}
				catch
				{
					XmlTextWriter xtw = new XmlTextWriter("opctask.xml", Encoding.UTF8);
					//新建XML文件        
					xtw.WriteStartDocument();

					xtw.WriteStartElement("Tasks");
					xtw.WriteEndElement();
					
					xtw.WriteEndDocument();
					xtw.Close();
					xmlDocument.Load("opctask.xml");
				}

				//先删除Tasks下的所有节点
				XmlNode root = xmlDocument.SelectSingleNode("Tasks");
				root.RemoveAll();

				//再逐一加入新的节点
				for (int i = 0; i < cargoLoadTaskNames.Count; i++)
				{
					string tagname = cargoLoadTaskNames[i];
					XmlElement xe = xmlDocument.CreateElement("Task");
					xe.SetAttribute("Name", tagname);

					List<string> cargoLoadTaskCloseValvei = cargoLoadTaskCloseValves[i];
					List<string> cargoLoadTaskOpenValvei = cargoLoadTaskOpenValves[i];
					for (int j=0;j< cargoLoadTaskCloseValvei.Count;j++)
					{
						XmlElement xeSub1 = xmlDocument.CreateElement("Tag");
						string opctag = cargoLoadTaskCloseValvei[j];
						xeSub1.SetAttribute("OPCTag", opctag);
						xeSub1.SetAttribute("OpcType", "Boolean");
						xeSub1.SetAttribute("Value", "1");
						xe.AppendChild(xeSub1);
					}
					for (int j = 0; j < cargoLoadTaskOpenValvei.Count; j++)
					{
						XmlElement xeSub1 = xmlDocument.CreateElement("tag");
						string opctag = cargoLoadTaskOpenValvei[j];
						xeSub1.SetAttribute("OPCTag", opctag);
						xeSub1.SetAttribute("OpcType", "Boolean");
						xeSub1.SetAttribute("Value", "1");
						xe.AppendChild(xeSub1);
					}
					root.AppendChild(xe);
				}
				xmlDocument.Save("opctask.xml");

				//最后更新panelTask
				panelTask.Children.Clear();
				allTaskList = GetTaskList();
				taskList.Clear();
				if (allTaskList.Count > 0)
				{
					OpcTask task0 = allTaskList[0];
					List<OPCTag> controlList = task0.TagList;
					foreach (OPCTag tag in controlList)
					{
						viewModel.SetOpcTagValue_CtrlPnts(tag.OpcName, DateTime.MinValue, string.Empty, string.Empty, Colors.Red);
					}
				}
				//DEBUG 此处应该加上根据测点状态判断按键状态的逻辑，但该功能仅用于测试，故省略该步骤
				Style btnTaskStyle = (Style)FindResource("btnTaskStyle");
				foreach (OpcTask opcTask in allTaskList)
				{
					bool checkres = false;
					foreach (OpcTask opcTask0 in taskList)
					{
						if (opcTask0.TaskName == opcTask.TaskName)
						{
							checkres = true;
							break;
						}
					}
					if (checkres)
					{
						for (int i = 0; i < panelTask.Children.Count; i++)
						{
							Button btnTask = (Button)panelTask.Children[i];
							List<OpcTaskStatus> opcTasks = (List<OpcTaskStatus>)btnTask.Tag;
							OpcTaskStatus opcTaskStatus = new OpcTaskStatus();
							opcTaskStatus.TaskStatus = false;
							opcTaskStatus.OpcTask = opcTask;
							opcTasks.Add(opcTaskStatus);
						}
					}
					else
					{
						Button btnTask = new Button();
						btnTask.Content = opcTask.TaskName;
						btnTask.Click += BtnTask_Click;

						List<OpcTaskStatus> opcTasks = new List<OpcTaskStatus>();
						OpcTaskStatus opcTaskStatus = new OpcTaskStatus();
						opcTaskStatus.TaskStatus = false;
						opcTaskStatus.OpcTask = opcTask;
						opcTasks.Add(opcTaskStatus);
						btnTask.Tag = opcTasks;

						btnTask.Style = btnTaskStyle;
						panelTask.Children.Add(btnTask);
						taskList.Add(opcTask);
					}
				}
			}
			return;
        }

		private void UpdateBtnCommPnts_Click(object sender, RoutedEventArgs e)
		{
			//DEBUG 这里改为根据通讯测点表自动向对应的通讯点下发信号
			string path = "./commpnts.csv";
			List<string[]> commpnts = TaskUtils.ReadExcel(path);

			foreach (string[] commpnt in commpnts)
			{
				string add = commpnt[1];
				string type = commpnt[3];
				int value = Convert.ToInt32(commpnt[6]);
				string status_tag = string.Format("{0}{1}", SysConfig.OPC_ADD_PRE, add);
				Dictionary<string, object> openComDic = new Dictionary<string, object>();
				openComDic.Add(status_tag, value);
				opcUtil.SetOpcValues(openComDic);
			}
			//Dictionary<string, object> openComDic = new Dictionary<string, object>();
			//openComDic.Add("ns=2;s=S7-1500RH-System_1.PLC_1.DB000.OpcAnalogData[81].Value", 1);
			//opcUtil.SetOpcValues(openComDic);

			MessageBox.Show("重置通讯点完成");
		}

		private void TaskTimer_Tick(object sender, EventArgs e)
        {
			//NOTICE
			UpdateOpcValues_TankStatus(TankConstant.tagList_tankStatus);
			UpdateOpcValues_FlammableGasStatus(TankConstant.tagList_flammableGasStatus);
			UpdateOpcValues_ValveStatus(TankConstant.tagList_valveStatus);
			UpdateOpcValues_PumpStatus(TankConstant.tagList_pumpStatus);
			UpdateOpcValues_HardwireStatus(TankConstant.tagList_hardwireStatus);
			//UpdateOpcValues_CtrlPnts(controlList);
		}
		private List<OpcTask> GetTaskList()
        {
            List<OpcTask> taskList = new List<OpcTask>();

			try
			{
                XmlDocument xml = new XmlDocument();
                xml.Load("./opctask.xml");
                XmlNodeList nodeList = xml.SelectNodes("/Tasks/Task");
                foreach(XmlNode task in nodeList)
                {
                    OpcTask opcTask = new OpcTask();
                    opcTask.TaskName = task.Attributes["Name"].Value;
                    opcTask.TagList = new List<OPCTag>();
                    foreach(XmlNode tag in task.ChildNodes)
                    {
                        string opcType = tag.Attributes["OpcType"].Value.Trim().ToLower();
                        string opcValue = tag.Attributes["Value"].Value.Trim();

                        OPCTag opcTag = new OPCTag();
                        opcTag.OpcName = tag.Attributes["OPCTag"].Value.Trim();
                        opcTag.OpcType = opcType;
                        opcTag.OpcValue = new DataValue();

						switch (opcType)
						{
							case "byte": opcTag.OpcValue.Value = Convert.ToByte(opcValue); break;
							case "sbyte": opcTag.OpcValue.Value = Convert.ToSByte(opcValue); break;
							case "short": opcTag.OpcValue.Value = Convert.ToInt16(opcValue); break;
							case "ushort": opcTag.OpcValue.Value = Convert.ToUInt16(opcValue); break;
							case "int": opcTag.OpcValue.Value = Convert.ToInt32(opcValue); break;
							case "uint": opcTag.OpcValue.Value = Convert.ToUInt32(opcValue); break;
							case "long": opcTag.OpcValue.Value = Convert.ToInt64(opcValue); break;
							case "ulong": opcTag.OpcValue.Value = Convert.ToUInt64(opcValue); break;
							case "real": opcTag.OpcValue.Value = Convert.ToSingle(opcValue); break;
							case "bin":
								{
									opcTag.OpcValue.Value = opcValue.PadLeft(16, '0'); 
									break;
								}
						}

						opcTask.TagList.Add(opcTag);
                    }
                    taskList.Add(opcTask);
                }
            }
            catch(Exception ex)
            {
				CommUtil.AddSystemLog(7, 0, ex.Message);
			}

			return taskList;
        }
        private void UpdateOpcValues_TankStatus(List<OPCTag> tmpTagList)
        {
			string value_str_output = string.Empty;
            foreach (OPCTag tag in tmpTagList)
            {
                if (tag.OpcValue != null && tag.OpcValue.Value != null)
                {
                    DateTime tstamp = DateTime.Now;
                    if (Math.Abs((DateTime.Now - tag.OpcValue.ServerTimestamp).TotalHours) < 24)
                    {
                        tstamp = tag.OpcValue.ServerTimestamp;
                    }

                    string valStr = tag.OpcValue.Value.ToString();

					double tmpValue = Convert.ToDouble(valStr);

					value_str_output += string.Format("{0}  {1} // ", tag.DispName, valStr);

					string qualitystr = DataValue.IsGood(tag.OpcValue) ? "Good" : "Bad";
                    Color bgcolor = Colors.Red;
                    if (qualitystr == "Good")
                        bgcolor = Colors.Green;

					string name = tag.OpcName;
					if (tag.DispName != null)
						name = tag.DispName;

					string type = tag.OpcType;
					if(type == "bin")
					{
						valStr = Convert.ToString(Convert.ToInt16(valStr), 2).PadLeft(16, '0');
						if (name.IndexOf("@") > -1)
						{
							int pos0 = name.IndexOf("@") + 1;
							int pos = Convert.ToInt16(name.Substring(pos0, 1));
							valStr = valStr.Substring(valStr.Length - pos - 1, 1);
							bool check = Convert.ToBoolean(Convert.ToInt16(valStr));
							if (check)
								bgcolor = Colors.Orange;
						}
					}
					viewModel.SetOpcTagValue_TankStatus(name, tstamp, valStr, qualitystr, bgcolor);
				}
            }
			if(TankConstant.g_Debug)
			{
				//TankConstant.MyDataLog.appendText(value_str_output);
				//Console.WriteLine(value_str_output);
			}
        }
        private void UpdateOpcValues_ValveStatus(List<OPCTag> tmpTagList)
        {
            foreach (OPCTag tag in tmpTagList)
            {
                if (tag.OpcValue != null && tag.OpcValue.Value != null)
                {
                    DateTime tstamp = DateTime.Now;
                    if (Math.Abs((DateTime.Now - tag.OpcValue.ServerTimestamp).TotalHours) < 24)
                    {
                        tstamp = tag.OpcValue.ServerTimestamp;
                    }

                    string valStr = tag.OpcValue.Value.ToString();
                    string qualitystr = DataValue.IsGood(tag.OpcValue) ? "Good" : "Bad";
                    Color bgcolor = Colors.Red;
                    if (qualitystr == "Good")
                        bgcolor = Colors.Green;

					string name = tag.OpcName;
					if (tag.DispName != null)
						name = tag.DispName;

                    string type = tag.OpcType;
                    if (type == "bin")
                    {
                        valStr = Convert.ToString(Convert.ToInt16(valStr), 2).PadLeft(16, '0');
                        if (name.IndexOf("@") > -1)
                        {
                            int pos0 = name.IndexOf("@") + 1;
                            int pos = Convert.ToInt16(name.Substring(pos0, 1));
                            valStr = valStr.Substring(valStr.Length - pos - 1, 1);
                            bool check = Convert.ToBoolean(Convert.ToInt16(valStr));
                            if (check)
                                bgcolor = Colors.Orange;
                        }
                    }
					else
					{
						bool check = Convert.ToBoolean(Convert.ToInt16(valStr));
						if (check)
							bgcolor = Colors.Orange;

					}
					viewModel.SetOpcTagValue_ValveStatus(name, tstamp, valStr, qualitystr, bgcolor);
                }
            }
        }
        private void UpdateOpcValues_PumpStatus(List<OPCTag> tmpTagList)
        {
            foreach (OPCTag tag in tmpTagList)
            {
                if (tag.OpcValue != null && tag.OpcValue.Value != null)
                {
                    DateTime tstamp = DateTime.Now;
                    if (Math.Abs((DateTime.Now - tag.OpcValue.ServerTimestamp).TotalHours) < 24)
                    {
                        tstamp = tag.OpcValue.ServerTimestamp;
                    }

                    string valStr = tag.OpcValue.Value.ToString();
                    string qualitystr = DataValue.IsGood(tag.OpcValue) ? "Good" : "Bad";
                    Color bgcolor = Colors.Red;
                    if (qualitystr == "Good")
                        bgcolor = Colors.Green;

					string name = tag.OpcName;
					if (tag.DispName != null)
						name = tag.DispName;

                    string type = tag.OpcType;
                    if (type == "bin")
                    {
                        valStr = Convert.ToString(Convert.ToInt16(valStr), 2).PadLeft(16, '0');
                        if (name.IndexOf("@") > -1)
                        {
                            int pos0 = name.IndexOf("@") + 1;
                            int pos = Convert.ToInt16(name.Substring(pos0, 1));
                            valStr = valStr.Substring(valStr.Length - pos - 1, 1);
                            bool check = Convert.ToBoolean(Convert.ToInt16(valStr));
                            if (check)
                                bgcolor = Colors.Orange;
                        }
                    }
					else
					{
						bool check = Convert.ToBoolean(Convert.ToInt16(valStr));
						if (check)
							bgcolor = Colors.Orange;

					}
					viewModel.SetOpcTagValue_PumpStatus(name, tstamp, valStr, qualitystr, bgcolor);
                }
            }
        }
        private void UpdateOpcValues_HardwireStatus(List<OPCTag> tmpTagList)
        {
			string output = "HardWireStatus = ";
			foreach (OPCTag tag in tmpTagList)
            {
                if (tag.OpcValue != null && tag.OpcValue.Value != null)
                {
                    DateTime tstamp = DateTime.Now;
                    if (Math.Abs((DateTime.Now - tag.OpcValue.ServerTimestamp).TotalHours) < 24)
                    {
                        tstamp = tag.OpcValue.ServerTimestamp;
                    }

					if (tag.OpcValue.Value == null)
					{
						output += string.Format("{0}:{1} \n", tag.OpcName, tag.DispName);
						continue;
					}

					string valStr = Convert.ToString(tag.OpcValue.Value.ToString());
                    string qualitystr = DataValue.IsGood(tag.OpcValue) ? "Good" : "Bad";
                    Color bgcolor = Colors.Red;
                    if (qualitystr == "Good")
                        bgcolor = Colors.Green;
					string name = tag.OpcName;
					if (tag.DispName != null)
						name = tag.DispName;

                    string type = tag.OpcType.ToUpper();
                    if (type.Contains("BIN"))
                    {
                        valStr = Convert.ToString(Convert.ToInt16(valStr), 2).PadLeft(16, '0');
                        if (name.IndexOf("@") > -1)
                        {
                            int pos0 = name.IndexOf("@") + 1;
                            int pos = Convert.ToInt16(name.Substring(pos0, 1));
                            valStr = valStr.Substring(valStr.Length - pos - 1, 1);
                            bool check = Convert.ToBoolean(Convert.ToInt16(valStr));
                            if (check)
                                bgcolor = Colors.Orange;
                        }
                    }
					else if(type.Contains("BOOL"))
					{
						//船上下位机设置bool型，传到上位机显示的不是0/1，而是false和true
						bool check = true;
						string tmpstr = valStr.ToUpper();
						if (tmpstr.Contains("FALSE"))
							check = false;
						if (check)
							bgcolor = Colors.Orange;
					}
					else
					{
						valStr = Convert.ToString(Convert.ToDouble(valStr)* TankConstant.TANKLEVEL_PARAM);
					}
					viewModel.SetOpcTagValue_HardwireStatus(name, tstamp, valStr, qualitystr, bgcolor);

					output += string.Format("{0}:{1} \n", tag.OpcName, tag.DispName);
				}
			}
			if (TankConstant.g_Debug)
			{
				//TankConstant.MyLog.appendText(output);
				//Console.WriteLine(output);
			}
		}
		private void UpdateOpcValues_FlammableGasStatus(List<OPCTag> tmpTagList)
		{
			string output = "GasStatus = ";
			foreach (OPCTag tag in tmpTagList)
			{
				if (tag.OpcValue != null && tag.OpcValue.Value != null)
				{
					DateTime tstamp = DateTime.Now;
					if (Math.Abs((DateTime.Now - tag.OpcValue.ServerTimestamp).TotalHours) < 24)
					{
						tstamp = tag.OpcValue.ServerTimestamp;
					}

					if (tag.OpcValue.Value == null)
					{
						output += string.Format("{0}:{1} \n", tag.OpcName, tag.DispName);
						continue;
					}

					string valStr = Convert.ToString(tag.OpcValue.Value);
					string qualitystr = DataValue.IsGood(tag.OpcValue) ? "Good" : "Bad";
					Color bgcolor = Colors.Red;
					if (qualitystr == "Good")
						bgcolor = Colors.Green;
						
					string name = tag.OpcName;
					if (tag.DispName != null)
						name = tag.DispName;

					string type = tag.OpcType.ToUpper();
					if (type.Contains("BIN"))
					{
						valStr = Convert.ToString(Convert.ToInt16(valStr), 2).PadLeft(16, '0');
						if (name.IndexOf("@") > -1)
						{
							int pos0 = name.IndexOf("@") + 1;
							int pos = Convert.ToInt16(name.Substring(pos0, 1));
							valStr = valStr.Substring(valStr.Length - pos - 1, 1);
							bool check = Convert.ToBoolean(Convert.ToInt16(valStr));
							if (check)
								bgcolor = Colors.Orange;
						}
					}
					else if (type.Contains("BOOL"))
					{
						//船上下位机设置bool型，传到上位机显示的不是0/1，而是false和true
						bool check = true;
						string tmpstr = valStr.ToUpper();
						if (tmpstr.Contains("FALSE"))
							check = false;
						if (check)
							bgcolor = Colors.Orange;
					}
					else
					{
						valStr = Convert.ToString(Convert.ToDouble(valStr) * TankConstant.TANKLEVEL_PARAM);
					}
					viewModel.SetOpcTagValue_FlammableGasStatus(name, tstamp, valStr, qualitystr, bgcolor);

					output += string.Format("{0}:{1} \n", tag.OpcName, tag.DispName);
				}
			}
			if (TankConstant.g_Debug)
			{
				//TankConstant.MyLog.appendText(output);
				//Console.WriteLine(output);
			}
		}

		private void UpdateOpcValues_CtrlPnts(List<OPCTag> tmpTagList)
        {
            if (tmpTagList != null && tmpTagList.Count > 0)
            {
				opcUtil.GetOpcValues(tmpTagList);

                foreach (OPCTag tag in tmpTagList)
                {
                    if (tag.OpcValue != null && tag.OpcValue.Value != null)
                    {
                        DateTime tstamp = DateTime.Now;
                        if (Math.Abs((DateTime.Now - tag.OpcValue.ServerTimestamp).TotalHours) < 24)
                        {
                            tstamp = tag.OpcValue.ServerTimestamp;
                        }

                        string valStr = tag.OpcValue.Value.ToString();
                        string qualitystr = DataValue.IsGood(tag.OpcValue) ? "Good" : "Bad";
                        Color bgcolor = Colors.Red;
                        if (qualitystr == "Good")
                            bgcolor = Colors.Green;
						viewModel.SetOpcTagValue_CtrlPnts(tag.OpcName, tstamp, valStr, qualitystr, bgcolor);
                    }
                }
            }
        }
		private void GridView_TankStatusUpdate_Click(object sender, RoutedEventArgs e)
		{
			string opc_add = (sender as Button).Content.ToString();

			foreach (OPCTag tag in TankConstant.tagList_tankStatus)
			{
				if (tag.DispName.Contains(opc_add))
				{
					string opcname = tag.OpcName;
					DataValue ori_status_data = tag.OpcValue;
					string status_type = tag.OpcType.ToUpper();
					string status_tag = string.Format("{0}{1}", SysConfig.OPC_ADD_PRE, opcname);
					Int32 send_value = 0;
					if (status_type.Contains("BOOL"))
					{
						bool ori_status_value = Convert.ToBoolean(ori_status_data.Value);
						bool send_status_value = !ori_status_value;
						send_value = Convert.ToInt32(send_status_value);
					}
					else if (status_type.Contains("INT"))
					{
						Int32 ori_status_value = Convert.ToInt32(ori_status_data.Value);
						Int32 send_status_value = ori_status_value;
						if (send_status_value > 0)
							send_status_value = 0;
						else
							send_status_value = 10;
						send_value = Convert.ToInt32(send_status_value);
					}

					var dialgoResult = MessageBox.Show("确认修改信号下发?", "提示", MessageBoxButton.YesNo);
					if (dialgoResult == MessageBoxResult.Yes)
						App.UaClient.WriteNode<Int32>(status_tag, send_value);
					return;
				}
			}
		}
		private void GridView_ValveStatusUpdate_Click(object sender, RoutedEventArgs e)
		{
			string opc_add = (sender as Button).Content.ToString();

			foreach (OPCTag tag in TankConstant.tagList_valveStatus)
			{
				if (tag.DispName.Contains(opc_add))
				{
					string opcname = tag.OpcName;
					DataValue ori_status_data = tag.OpcValue;
					string status_type = tag.OpcType.ToUpper();
					string status_tag = string.Format("{0}{1}", SysConfig.OPC_ADD_PRE, opcname);

					var dialgoResult = MessageBox.Show("确认修改信号下发?", "提示", MessageBoxButton.YesNo);
					if (dialgoResult == MessageBoxResult.Yes)
					{
						//DEBUG 当前下位机整型均为int，对应上位机int16,；如下位机整型为DInt，则对应上位机int32
						if (status_type.Contains("BOOL"))
						{
							bool ori_status_value = Convert.ToBoolean(ori_status_data.Value);
							bool send_status_value = !ori_status_value;
							//App.UaClient.WriteNode<Int32>(status_tag, Convert.ToInt32(send_status_value));
							//App.UaClient.WriteNode<Boolean>(status_tag, send_status_value);
							App.UaClient.WriteNode<Int16>(status_tag, Convert.ToInt16(send_status_value));
						}
						else if (status_type.Contains("INT"))
						{
							Int16 ori_status_value = Convert.ToInt16(ori_status_data.Value);
							Int16 send_status_value = ori_status_value;
							if (send_status_value > 0)
								send_status_value = 0;
							else
								send_status_value = 10;
							App.UaClient.WriteNode<Int32>(status_tag, Convert.ToInt32(send_status_value));
							//App.UaClient.WriteNode<Int16>(status_tag, send_status_value);
						}
						else
						{
							MessageBox.Show("数据类型不符，当前仅支持BOOL和INT16");
						}
					}
					return;
				}
			}
		}
		private void GridView_PumpStatusUpdate_Click(object sender, RoutedEventArgs e)
		{
			string opc_add = (sender as Button).Content.ToString();

			foreach (OPCTag tag in TankConstant.tagList_pumpStatus)
			{
				if (tag.DispName.Contains(opc_add))
				{
					string opcname = tag.OpcName;
					DataValue ori_status_data = tag.OpcValue;
					string status_type = tag.OpcType.ToUpper();
					string status_tag = string.Format("{0}{1}", SysConfig.OPC_ADD_PRE, opcname);
					Int32 send_value = 0;
					if (status_type.Contains("BOOL"))
					{
						bool ori_status_value = Convert.ToBoolean(ori_status_data.Value);
						bool send_status_value = !ori_status_value;
						send_value = Convert.ToInt32(send_status_value);
					}
					else if (status_type.Contains("INT"))
					{
						Int32 ori_status_value = Convert.ToInt32(ori_status_data.Value);
						Int32 send_status_value = ori_status_value;
						if (send_status_value > 0)
							send_status_value = 0;
						else
							send_status_value = 10;
						send_value = Convert.ToInt32(send_status_value);
					}
					var dialgoResult = MessageBox.Show("确认修改信号下发?", "提示", MessageBoxButton.YesNo);
					if (dialgoResult == MessageBoxResult.Yes)
						App.UaClient.WriteNode<Int32>(status_tag, send_value);
					return;
				}
			}
		}
		private void GridView_HardwireStatusUpdate_Click(object sender, RoutedEventArgs e)
		{
			string opc_add = (sender as Button).Content.ToString();

			foreach (OPCTag tag in TankConstant.tagList_hardwireStatus)
			{
				if (tag.DispName.Contains(opc_add))
				{
					string opcname = tag.OpcName;
					DataValue ori_status_data = tag.OpcValue;
					string status_type = tag.OpcType.ToUpper();
					string status_tag = string.Format("{0}{1}", SysConfig.OPC_ADD_PRE, opcname);
					Int32 send_value = 0;
					if (status_type.Contains("BOOL"))
					{
						bool ori_status_value = Convert.ToBoolean(ori_status_data.Value);
						bool send_status_value = !ori_status_value;
						send_value = Convert.ToInt32(send_status_value);
					}
					else if (status_type.Contains("INT"))
					{
						Int32 ori_status_value = Convert.ToInt32(ori_status_data.Value);
						Int32 send_status_value = ori_status_value;
						if (send_status_value > 0)
							send_status_value = 0;
						else
							send_status_value = 10;
						send_value = Convert.ToInt32(send_status_value);
					}
					var dialgoResult = MessageBox.Show("确认修改信号下发?", "提示", MessageBoxButton.YesNo);
					if (dialgoResult == MessageBoxResult.Yes)
						App.UaClient.WriteNode<Int32>(status_tag, send_value);
					return;
				}
			}
		}
		private void GridView_FlammableGasStatusUpdate_Click(object sender, RoutedEventArgs e)
		{
			string opc_add = (sender as Button).Content.ToString();

			foreach (OPCTag tag in TankConstant.tagList_flammableGasStatus)
			{
				if (tag.DispName.Contains(opc_add))
				{
					string opcname = tag.OpcName;
					DataValue ori_status_data = tag.OpcValue;
					string status_type = tag.OpcType.ToUpper();
					string status_tag = string.Format("{0}{1}", SysConfig.OPC_ADD_PRE, opcname);
					Int32 send_value = 0;
					if (status_type.Contains("BOOL"))
					{
						bool ori_status_value = Convert.ToBoolean(ori_status_data.Value);
						bool send_status_value = !ori_status_value;
						send_value = Convert.ToInt32(send_status_value);
					}
					else if (status_type.Contains("INT"))
					{
						Int32 ori_status_value = Convert.ToInt32(ori_status_data.Value);
						Int32 send_status_value = ori_status_value;
						if (send_status_value > 0)
							send_status_value = 0;
						else
							send_status_value = 10;
						send_value = Convert.ToInt32(send_status_value);
					}
					var dialgoResult = MessageBox.Show("确认修改信号下发?", "提示", MessageBoxButton.YesNo);
					if (dialgoResult == MessageBoxResult.Yes)
						App.UaClient.WriteNode<Int32>(status_tag, send_value);
					return;
				}
			}
		}
		private void OPCMonitorView_Loaded(object sender, RoutedEventArgs e)
		{
			if(taskTimer != null)
				taskTimer.Start();
		}
		private void OPCMonitorView_Unloaded(object sender, RoutedEventArgs e)
		{
			//if (taskTimer != null)
			//	taskTimer.Stop();
		}

		private void CheckTaskTimer_Tick(object sender, EventArgs e)
		{
			if(TankConstant.tagList_hardwireStatus.Count > 0)
			{
				double a = 0;
			}
			return;
		}
	}
}
